
// serves for implicitly converted to that type when certain operations cannot be performed, 
// e.g  2+Mat
package scalaSci


class RichNumber(v: Double) {
    private val  value = v    // the RichNumber includes a Double field that corresponds to its value


  def +(that: Array[Double]): Array[Double] = {
    var   N  =  that.length
    
    var result = new Array[Double](N)
     for (r <-0 until  N)  
         result(r) = that(r) + value
 
    result
    
  }
  

  def -(that: Array[Double]): Array[Double] = {
    var   N  =  that.length
    
    var result = new Array[Double](N)
     for (r <-0 until  N)  
         result(r) = -that(r) + value
 
    result
    
  }
  

  
 def *(that: Array[Double]): Array[Double] = {
    var   N  =  that.length
    
    var result = new Array[Double](N)
     for (r <-0 until  N)  
         result(r) = that(r) * value
 
    result
    
  }
  

  

 def /( that:  Array[Double]): Array[Double]= {
    var   N  =  that.length
    
   var result = new Array[Double](N)
   var r=0
   while (r < N)  {
        var tmp = that(r)
        if (tmp != 0)
            result(r) = value /  tmp
        else
            result(r) = 0.0
         r += 1
       }
      
    result
 }

  


  def +(that: Array[Array[Double]]): Array[Array[Double]] = {
    var   N  =  that.length
    var   M = that(0).length

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r)(c) + value
 
    result
    
  }
  

  def -(that: Array[Array[Double]]): Array[Array[Double]] = {
    var   N  =  that.length
    var   M = that(0).length

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = -that(r)(c) + value
 
    result
    
  }
  
  
  
  def *(that: Array[Array[Double]]): Array[Array[Double]] = {
    var   N  =  that.length
    var   M = that(0).length

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r)(c) * value
 
    result
    
  }
  

 def /( that:  Array[Array[Double]]): Array[Array[Double]]= {
    var   N  =  that.length
    var   M = that(0).length

   var result = new Array[Array[Double]](M, N)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
        var tmp = that(r)(c)
        if (tmp != 0)
            result(r)(c) = value /  tmp
        else
            result(r)(c) = 0.0
         c += 1
       }
      r += 1
    }
    result
 }

  
  
 // addition of RichNumber and Vec
 def +( that:  Vec ): Vec = {
   var   N  =  that.length
    
   var result = new Vec(N)
   var r=0
   while (r < N)   {
         result(r) = that(r) + value
         r += 1
       }
    result 
 }

   // subtraction of Vec from a RichNumber 
 def -( that:  Vec ): Vec = {
   var   N  =  that.length
    
   var result = new Vec(N)
   var r=0
   while (r < N)   {
         result(r) =  value - that(r) 
         r += 1
       }
    result
 }

  
 // multiplication of RichNumber and Vec
 def *( that:  Vec ): Vec = {
   var   N  =  that.length
    
   var result = new Vec(N)
   var r=0
   while (r < N)   {
         result(r) = that(r) * value
         r += 1
       }
    result
 }

  
 // division of a  RichNumber with a Vec
 def /( that:  Vec ): Vec = {
   var   N  =  that.length
    
   var result = new Vec(N)
   var r=0
   while (r < N)   {
         var tmp = that(r)
         if (tmp!=0)
            result(r) =  value / tmp
          else
            result(r) = 0.0
         r += 1
       }
    result
 }

  
   
  def +(that: Matrix): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) + value
 
    new Matrix(result, true)
    
  }
  
// subtraction of a Matrix from a RichNumber
  def -(that: Matrix): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) =  value - that(r,c) 
 
    new Matrix(result, true)
    
  }

  def *(that: Matrix): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) * value
 
    new Matrix(result, true)
    
  }
  

  
  // division of a RichNumber with a  Matrix. Divides the corresponding number with each of the Matrix's element'
 def /( that:  Matrix ): Matrix = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new Matrix(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
        var tmp = that(r, c)
        if (tmp != 0)
            result(r, c) = value /  tmp
        else
            result(r, c) = 0.0
         c += 1
       }
      r += 1
    }
    result
 }

  
   
  def +(that: Mat): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) + value
 
    new Mat(result, true)
    
  }
  
// subtraction of a Matrix from a RichNumber
  def -(that: Mat): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) =  value - that(r,c) 
 
    new Mat(result, true)
    
  }

  def *(that: Mat): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

    var result = new Array[Array[Double]](N,M)
     for (r <-0 until  N)  
       for (c <-0 until  M)  
         result(r)(c) = that(r,c) * value
 
    new Mat(result, true)
    
  }
  

  
  // division of a RichNumber with a  Matrix. Divides the corresponding number with each of the Matrix's element'
 def /( that:  Mat ): Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
        var tmp = that(r, c)
        if (tmp != 0)
            result(r, c) = value /  tmp
        else
            result(r, c) = 0.0
         c += 1
       }
      r += 1
    }
    result
 }

  
  
  // addition of RichNumber and an EJML.Mat
 def +( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
         result(r, c) = that(r,c) + value
         c += 1
       }
      r += 1
    }
    result
 }

  // subtraction of an EJML.Mat from a RichNumber
 def -( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
         result(r, c) = -that(r,c) + value
         c += 1
       }
      r += 1
    }
    result
 }

  // multiplication of a RichNumber with a Mat
 def *( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
         result(r, c) = that(r,c) * value
         c += 1
       }
      r += 1
    }
    result
 }

  
  // division of a RichNumber with a  Mat. Divides the corresponding number with each of the Mat's element'
 def /( that:  EJML.Mat ): EJML.Mat = {
    var   N  =  that.Nrows
    var   M = that.Ncols

   var result = new EJML.Mat(N, M)
   var r=0; var c=0
   while (r < N)  {
      c = 0
      while (c < M)  {
        var tmp = that(r, c)
        if (tmp != 0)
            result(r, c) = value /  tmp
        else
            result(r, c) = 0.0
         c += 1
       }
      r += 1
    }
    result
 }

  
  
  
}


